/********************************************************************************

    C++ Implementation of Symmetric Level-Index Arithmetic (see readme.txt for usage)
    Copyright (C) 2007  Xunyang Shen
    Email: xunyang.shen@gmail.com

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

**********************************************************************************/

#ifndef SLI_H
#define	SLI_H
#include <complex>
#include <iostream>
#include <iomanip>
#include <stdexcept>
#include <cstdlib>
#include <cmath>

class SLI  
{
	//constructor forces the use of SLI
	SLI(double a, char b);
	unsigned level   : 3;  //magnitude of level
	unsigned signl   : 1;  //sign of level
	unsigned signi   : 1;  //sign of index
	double index;          //magnitude of index
	//constructor used only in class routines
	SLI(unsigned slevel, double sindex, unsigned ssignl, unsigned ssigni);

public:
	//constructor to convert from a FLP number
	SLI(double a);
	//constructor with level + index as input
	SLI(short slevel, double sindex) throw(std::domain_error);
	SLI();
	
	//get level/index/signs
	unsigned GetLevel() const;
	unsigned GetSignl() const;
	unsigned GetSigni() const;
	double GetIndex() const;
	//get signed level/index
	short GetSignedLevel() const;
	double GetSignedIndex() const;
	//get decimal exponent/significand 
	double GetDecimalExp() const;
	double GetDecimalSig() const;

	//display a SLI number
	friend void display(const SLI& s);
	//display a SLI number in floating point form
	friend void dispfloat(const SLI& s);
	//convert to double
	double Double() const;
	//absolute value
	friend SLI abs(const SLI& s);
	//reciprocal
	SLI Rec() const;
	//unary minus
	SLI operator -() const;
	//exponential and logarithm functions
	friend SLI exp(const SLI& s);
	friend SLI log(const SLI& s);
	friend SLI log2(const SLI& s);
	friend SLI log10(const SLI& s);

	//relational operators
	friend bool operator ==(const SLI& p, const SLI& q);
	friend bool operator !=(const SLI& p, const SLI& q);
	friend bool operator >(const SLI& p, const SLI& q);
	friend bool operator <(const SLI& p, const SLI& q);
	friend bool operator >=(const SLI& p, const SLI& q);
	friend bool operator <=(const SLI& p, const SLI& q);

	//arithmetic operators
	friend SLI operator +(const SLI& p, const SLI& q);
	friend SLI operator -(const SLI& p, const SLI& q);
	friend SLI operator *(const SLI& p, const SLI& q);
	friend SLI operator /(const SLI& p, const SLI& q);
	SLI& operator +=(const SLI& s);
	SLI& operator -=(const SLI& s);
	SLI& operator *=(const SLI& s);
	SLI& operator /=(const SLI& s);
	friend SLI pow(const SLI& p, const SLI& q);
	friend SLI sqrt(const SLI& s);

	//Sum of N arguments
	friend void SLIsort(SLI** first, SLI** last);
	friend SLI sum(unsigned N, SLI **s);
	friend SLI precisesum(unsigned N, SLI **s);
	friend SLI sum(unsigned N, SLI *s);
	friend SLI precisesum(unsigned N, SLI *s);
};

//Convert SLI to double
double SLI2FLP(SLI s);

//Trig functions
double sin(const SLI& s);
double cos(const SLI& s);
double tan(const SLI& s);

//Inverse trig functions
SLI asin(const SLI& s);
double acos(const SLI& s);
SLI atan(const SLI& s);

//Hyperbolic trig functions
SLI sinh(const SLI& s);
SLI cosh(const SLI& s);
double tanh(const SLI& s);

// vector norms
SLI norm(unsigned N, SLI *s);
SLI norm(unsigned N, SLI *s, SLI p);

//Sum of N arguments
SLI sum(unsigned N, SLI start, ...);
SLI precisesum(unsigned N, SLI start, ...);

//Dot product
SLI dotproduct(unsigned N, SLI *a, SLI *b);

//Switch between two output formats in ostream
std::ostream& sliout(std::ostream& os);
std::ostream& flpout(std::ostream& os);
//ostream output
std::ostream& operator <<(std::ostream& os, const SLI& s);
std::ostream& operator <<(std::ostream& os, const std::complex<SLI>& c);

typedef SLI sli;
typedef std::complex<SLI> CSLI;
typedef std::complex<SLI> csli;

#endif
